/*
 * @Author: zhanyinjia
 * @Date: 2022-07-10 14:50:19
 * @LastEditTime: 2022-07-12 22:32:11
 * @LastEditors: zhanyinjia
 * @Description:
 * @FilePath: \ts\3-class.ts
 */
// 类 不同于函数，它是es6中的，但其实本质也是function

// 回顾es5的构造函数、原型、原型链；静态属性、实例属性、原型属性
/* function Pointer(x, y) {
    this.type = "point"
    this.x = x;
    this.y = y;
    this.getX = function () {
        console.log(this.x);
    }
}

Pointer.color = 'red'

Pointer.getColor = function () {
    console.log(this.color);
}

Pointer.prototype.getX = function () {
    console.log(this.x*2);
}

Pointer.prototype.getY = function () {
    console.log(this.y*2);
}

let p1 = new Pointer(10, 10);
let p2 = new Pointer(20, 20);
p1.getX();
p1.__proto__.getX();
p1.type = "line";
console.log(p1.type, p2.type);
p2.getY();
console.log(p2.getY === Pointer.prototype.getY)
*/

//----------------------------------------------------------------

// 实例上的属性需要先声明在使用，构造函数中的参数可以使用可选参数和剩余参数
/* class Pointer {
    public type: string = 'point'
    public x!: number; // 实例上的属性必须先声明，如果不写public也是默认有的
    public y!: number;
    public getY: () => void
    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
        this.getY = function () {
            console.log('实例方法', this.y);
        }
    }
    static color = 'red'
    static getColor() { console.log(this.color); }
    getX() {
        console.log('原型方法');
    }
}
let p = new Pointer(100, 200); */

//----------------------------------------------------------------

// 类的修饰符  public protected private readonly
// public 表示父类本身、子类、外部都可以访问这个属性
// protected 受保护的，父类本身、子类可以访问这个属性
// private 私有的，只有自己可以访问
// readonly 只读，不可修改
// 如果constructor被标识为private或protected，则此类不能被new；被标识成private则不能被子类继承

/* class Animal {
    public name!: string;
    public age!: number;
    constructor(name: string, age: number) {
        this.name = name;  // 父类可以访问
        this.age = age;
    }
}

// 可以通过参数属性来简化父类中的代码，上面的Animal等同下面的：
class Animal {
    constructor(public name: string, public age: number) {
        this.name = name;
        this.age = age;
    }
}

new Animal("dog", 10);

class Cat extends Animal {
    constructor(name: string, age: number) {
        super(name, age);
        console.log(this.name, this.age); // 子类可以访问
    }
}
let cat = new Cat('Tom', 10);
console.log(cat.name, cat.age); // 外部可以访问 */

//----------------------------------------------------------------

// readonly  仅读属性只能在constructor中被赋值
/* class Animal {
    constructor(public readonly name: string, public age: number) {
        this.name = name;
        this.age = age;
    }
    changeName(name: string) {
        this.name = name; // 仅读属性只能在constructor中被赋值
    }
}
class Cat extends Animal {
    constructor(name: string, age: number) {
        super(name, age);
    }
}
let cat = new Cat('Tom', 10);
cat.changeName('Jerry'); */

//----------------------------------------------------------------

// 静态属性和静态方法  通过类来调用（是可以被继承的）
/* class Animal {
    private _name: string = 'Tom';   //实例属性
    get name() { // 原型上的方法  借助属性访问器访问私有属性
        console.log(this === cat);  //this指向当前类的实例
        return this._name;
    }
    set name(newName: string) {
        this._name = newName;
    }
    static type = '动物'; // 静态属性
    static getName() { // 静态方法
        return this.type;
    }
    say() {   //原型方法
        console.log('动物说话');
    }
}

class Cat extends Animal {
    constructor() {
        super();   //Animal.call
    }
    static getName() { // 子类重写父类方法
        console.log(super.getName());  //静态方法中的super指代的是父类
        return '猫';
    }
    say() {
        super.say();   // super指代的Animal.prototype
        console.log('猫说话');
    }
}

console.log(Cat.getName());

let cat = new Cat();
console.log(cat.name);
console.log(cat.say()); */

// 如果再有LittleCat继承Cat的话，静态方法和原型方法中不能super.super去调用父类的方法，只能一层一层调，js是单继承的
// 父类 => 子类 => 孙子类
// 父类可以有多个子类，子类只能有一个父类